#pragma ident "$Id XY. CAO. 2016-11-24 $"

/**
 * @file MGEXDCBReader.hpp
 * Class to read DCB data from MGEX CAS/DLR.
 */

#ifndef GPSTK_MGEXDCBREADER_HPP
#define GPSTK_MGEXDCBREADER_HPP

//============================================================================
//
//  Copyright (c) 
//
//  XY. CAO, Wuhan Uniersity, 2016 
//============================================================================
//

#include <iostream>
#include <string>
#include <map>

#include "Exception.hpp"
#include "FFTextStream.hpp"
#include "StringUtils.hpp"
#include "SatID.hpp"
//#include "RinexObsID.hpp"
#include "CommonTime.hpp"


namespace gpstk
{

	NEW_EXCEPTION_CLASS(DCBTypeNotFound, gpstk::Exception);

   class MGEXDCBReader : public FFTextStream
   {
   public:

         // Default constructor
	   MGEXDCBReader();
  

	   /// Validity bits for MGEX DCB file
	   enum validBits
	   {
		   validVersion          =        0x1, ///<1 Header Lines (Mandatory)
		   validComment      =        0x2, ///<2 "COMMENT" optional
		   validReference      =        0x4, ///<3 +FILE/REFERENCE(Mandatory)
		   validDescription    =        0x8, ///<4 +FILE/DESCRIPTION(Mandatory)
		   validSolution          =        0x10,///<5 +BIAS/SOLUTION(Mandatory)
		   allValid                     =        0x1D, 
	   };


	   /// @name MGEXDCBReader
	   //@{	   
	   double version;                              ///< Four digits indicating the version of SINEX_BIAS format used.	   
	   std::string agency;                          ///< Identify the agency creating the file
	   std::vector<std::string> commentList;        ///< comments in header (optional)

	   unsigned long valid;           ///< bits set when header rec.s present & valid

	   bool validEoH;                 ///< true if found END OF HEADER
	   //@}



	   // unit in ns
	   struct bias
	   {
		   double value;
		   double std;
	   };

	   typedef std::map< std::string, bias> TypeBias;

	   typedef std::map< SatID,TypeBias > satTypeBias;

	   typedef std::map< SatID::SatelliteSystem,TypeBias > rcvTypeBias;

	   typedef std::map< std::string,rcvTypeBias> rcvSysTypeBias;

	   // add any typeID into this struct( W = P )
	   /*
	   struct MGEXDCBGPS
	   {
		   std::vector< bias > C1C_C1W;
		   std::vector< bias > C1C_C2W;
		   std::vector< bias > C1C_C5Q;
		   std::vector< bias > C1C_C5X;
		   std::vector< bias > C1W_C2W;// P1-P2
		   std::vector< bias > C2C_C2W;
		   std::vector< bias > C2W_C2S;
		   std::vector< bias > C2W_C2L;
		   std::vector< bias > C2W_C2X;
		   // add 
	   };


	   // add any typeID into this struct( P = P )
	   struct MGEXDCBGLO
	   {
		   std::vector< bias > C1C_C1P;
		   std::vector< bias > C1C_C2C;
		   std::vector< bias > C1C_C2P;
		   std::vector< bias > C1P_C2P;// P1-P2
		   std::vector< bias > C2C_C2P;
		   // add 
	   };


	   // add any typeID into this struct( X = P )
	   struct MGEXDCBGAL
	   {
		   std::vector< bias > C1C_C5Q;
		   std::vector< bias > C1C_C7Q;
		   std::vector< bias > C1C_C8Q;
		   std::vector< bias > C1X_C5X;// P1-P2
		   std::vector< bias > C1X_C7X;
		   std::vector< bias > C1X_C8X;
		   // add 
	   };


	   // add any typeID into this struct( I = P )
	   struct MGEXDCBBDS
	   {
		   std::vector< bias > C2I_C7I;// P1-P2
		   std::vector< bias > C2I_C6I;
		   std::vector< bias > C7I_C6I;
		   // add 
	   };

	   struct MGEXDCB
	   {
		   std::vector< MGEXDCBGPS > GPSdcb;
		   std::vector< MGEXDCBGLO > GLOdcb;
		   std::vector< MGEXDCBGAL > GALdcb;
		   std::vector< MGEXDCBBDS > BDSdcb;
	   };
	   */

         /** Common constructor. It will always open file for read and will
          *  load DCB data in one pass.
          *
          * @param fn   DCB data file to read
          *
          */
      MGEXDCBReader(const char* fn)
         noexcept(false)
      {
		  try
		  {
			  FFTextStream(fn, std::ios::in);
			  if( !FFTextStream::is_open() )
			  {
				  GPSTK_THROW(FileMissingException("The DCB file " + std::string(fn) + 
								   "  does not exist!"));
			  }

			  loadData();
		  }
		  catch(FileMissingException& e)
		  {
			  GPSTK_RETHROW(e);
		  }
      };


         /** Common constructor. It will always open file for read and will
          *  load DCB data in one pass.
          *
          * @param fn   DCB data file to read
          *
          */
      MGEXDCBReader(const std::string& fn)
         noexcept(false)
      {
		  try
		  {
			  FFTextStream(fn, std::ios::in);
			  if( !FFTextStream::is_open() )
			  {
				  GPSTK_THROW(FileMissingException("The DCB file " + fn + 
								   "  does not exist!"));
			  }
			  
			  loadData();
		  }
		  catch(FileMissingException& e)
		  {
			  GPSTK_RETHROW(e);
		  }
      };

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Woverloaded-virtual"

         // Method to open AND load DCB data file.
      virtual void open(const char* fn)
         noexcept(false);


         // Method to open AND load DCB data file. It doesn't
         // clear data previously loaded.
      virtual void open(const std::string& fn)
         noexcept(false);

#pragma clang diagnostic pop


	  /** Get DCB data of a receiver
	  * @param    time    the time you desired
	  * @param    sat     the satellite you desired
	  * @param    type12  the type string, C1W-C2W..
	  * @return   dcb value and std
	  */
	  bias getSatDCB( const CommonTime& time,
		              const SatID& sat,
		              const std::string& type12);

      void clear()
      {
          satBiasData.clear();
          recBiasData.clear();
      }

         // Destructor
      virtual ~MGEXDCBReader() {};


   private:
  
	   // Map holding satellite DCB data
	   std::map< CommonTime, satTypeBias > satBiasData;

	   // Map holding receiver DCB file(different with sat)
	   std::map< CommonTime, rcvSysTypeBias > recBiasData;

	   // Method to store MGEX DCB data in this class' data map
	   virtual void loadData()
         noexcept(false);

   };  // End of class 'MGEXDCBReader'

       //@}

}  // End of namespace gpstk

#endif  // GPSTK_MGEXDCBREADER_HPP




